package com.cgs.query.handler.result

import com.cgs.query.domain.ParameterMapping
import com.cgs.query.handler.ResultSetHandler
import java.sql.CallableStatement
import java.sql.JDBCType
import java.sql.ResultSet
import java.sql.Statement

open class ListResultSetHandler : ResultSetHandler {

    override fun handleResultSet(hasResultSet: Boolean, stmt: Statement, limit: Int?): List<Any> {
        return if (hasResultSet) {
            transformList(stmt.resultSet, limit)
        } else {
            listOf(mapOf("AffectedRows" to stmt.updateCount))
        }
    }

    override fun handlerCyclingResultSets(hasResultSet: Boolean, stmt: Statement, limit: Int?): List<Any> {
        val result = arrayListOf<Any>()
        result.add(handleResultSet(hasResultSet, stmt, limit))
        while (true) {
            if (stmt.moreResults && stmt.updateCount == -1) {
                result.add(transformList(stmt.resultSet, limit))
            } else {
                if (stmt.updateCount == -1) {
                    return result
                } else {
                    result.add(listOf(mapOf("AffectedRows" to stmt.updateCount)))
                }
            }
        }
    }

    override fun handleOutputParameters(hasResultSet: Boolean, cs: CallableStatement, outParams: Map<Int, ParameterMapping>, limit: Int?): List<Any> {
        return if (outParams.isEmpty()) {
            handlerCyclingResultSets(hasResultSet, cs, limit)
        } else {
            val result = arrayListOf<Any>()
            for ((k, v) in outParams) {
                if (v.jdbcType == JDBCType.REF_CURSOR)
                    result.add(transformList((cs.getObject(k) as? ResultSet)!!, limit))
                else {
                    result.add(cs.getObject(k))
                }
            }
            return result
        }
    }

    open fun transformList(rs: ResultSet, limit: Int?): List<Any> {
        val list = arrayListOf<Any>()
        val colCount = rs.metaData.columnCount
        if (limit == null) {
            while (rs.next()) {
                list.add(mapRow(colCount, rs))
            }
        } else {
            var count = 0
            while (rs.next() && count < limit) {
                list.add(mapRow(colCount, rs))
                count++
            }
        }
        return list
    }

    open fun mapRow(colCount: Int, rs: ResultSet): Any {
        val array = arrayListOf<Any?>()
        for (i in 1..colCount) {
            array.add(rs.getObject(i))
        }
        return array
    }

    open fun firstList(data: List<Any>): List<Any> {
        return if (data.size == 1) {
            val first = data[0]
            if (first is List<*>) {
                first as List<Any>
            } else {
                data
            }
        } else
            data
    }
}